#[cfg(test)]
mod tests {
    // 非标识符的“标识符”
    // 根据我的理解，主要是讲 Rust 语法里的关键字在 macro_rules! 中可使用 ident 或者 tt 分类符来匹配。当然，不仅仅是这里例举的 self，可以是任何关键字。
    // 对于 _ ，它只能在模式中使用，声明宏中不能用 ident 分类符匹配， 而是用 pat 或者 tt 分类符。
    #[test]
    fn test_ident() {
        macro_rules! what_is {
            (self) => {"the keyword `self`"};
            ($i:ident) => {concat!("the identifier `", stringify!($i), "`")};
        }

        macro_rules! call_with_ident {
            ($c:ident($i:ident)) => {$c!($i)};
        }

        println!("{}", what_is!(self));
        println!("{}", call_with_ident!(what_is(self)));

        // 标记 @1
        //  call_with_ident! 要求一个标识符，而且它的确匹配到了，还成功替换了！ 所以，self 同时是一个关键词，但又不是。 你可能会想，好吧，但这鬼东西哪里重要呢？看看这个：
        println!("{:?}", Dummy(4).double().0);

        // 标记 @2
        // 所以说，宏在匹配的时候，会欣然把self当作标识符接受， 进而允许你把 self 带到那些实际上没办法使用的情况中去。
        // 但是，也成吧，既然得同时记住 self 既是关键词又是标识符， 那下面这个讲道理应该可行，对吧？
        // 实际上也不行，编译错误变成：
        println!("{:?}", Dummy(4)._double().0);

        // 标记 @3
        // 终于管用了。 所以说，self 是关键词，但如果想它变成标识符，那么同时也能是一个标识符。 那么，相同的道理对类似的其它东西有用吗？ 查看@4
        println!("{:?}", Dummy(4)._0_double().0);

    }

    macro_rules! make_mutable {
        ($i:ident) => {
            // let mut $i = $i; 取消注释查看 标记 @1
        };
    }

    macro_rules! make_self_mutable {
        ($i:ident) => {
            // let mut $i = self;   // 取消注释查看 标记 @2
        };
    }

    macro_rules! double_method {
        ($fn:ident, $self_:ident, $body:expr) => {
            fn $fn(mut $self_) -> Dummy {
                $body
            }
        };
    }


    struct Dummy(i32);

    impl Dummy {
        fn double(self) -> Dummy {
            make_mutable!(self);
            // self.0 *= 2;     取消注释查看 标记 @1
            self
        }

        fn _double(self) -> Dummy {
            // make_self_mutable!(self); // 取消注释查看 标记 @2
            // self.0 *= 2;
            self
        }

        double_method! {_0_double, self, {
            self.0 *= 2;
            self
        }}

        // 不可以 @4
        // double_method! {_underline_double, _, {
        //     self
        // }}
    }


}